package cool.xinya.ess.security;

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.StandardPasswordEncoder;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.Collection;
import java.util.LinkedHashMap;

@Configuration
public class ShiroConfig {
    @Autowired(required = false)
    private Collection<SessionListener> sessionListeners;
    @Resource
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${shiroFilter.anons}")
    private String[] anons;
    @Value("${shiroFilter.anyRole}")
    private String anyRole;
    @Value("${user.timeout}")
    private Long userTimeout;

    @Bean
    public StandardPasswordEncoder encoder() {
        return new StandardPasswordEncoder("weixinya");
    }

    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        CustomCredentialsMatcher matcher = new CustomCredentialsMatcher(encoder());
        userRealm.setCredentialsMatcher(matcher);
        userRealm.setCachingEnabled(false);

        return userRealm;
    }

    @Bean
    public CacheManager cacheManager() {
        return new RedisCacheManager(new RedisCache(redisTemplate));
    }

    @Bean
    public DefaultWebSessionManager sessionManager() {
        final DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // session 失效时间
        sessionManager.setGlobalSessionTimeout(userTimeout);
        // session 持久化存储
        sessionManager.setSessionDAO(new RedisSessionDAO(redisTemplate));
        // 添加session监听器
        if (sessionListeners != null && !sessionListeners.isEmpty()) {
            sessionManager.setSessionListeners(sessionListeners);
        }
        // 自动验证session是否失效,关闭
        sessionManager.setSessionValidationSchedulerEnabled(false);

        return sessionManager;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager() {
        final DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setSessionManager(sessionManager());
        securityManager.setRealm(userRealm());
//         securityManager.setCacheManager(cacheManager());
        return securityManager;
    }

    /**
     * 资源请求的过滤器配置
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter() {
        final ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager());
        // 配置权限类型和拦截器的对应关系
        final LinkedHashMap<String, Filter> filters = new LinkedHashMap<>();
        filters.put(CustomFilter.ANY_ROLES, new CustomRolesAuthorizationFilter(stringRedisTemplate));
        factoryBean.setFilters(filters);
        // 配置资源和权限类型的对应关系
        final LinkedHashMap<String, String> filterChains = new LinkedHashMap<>();
        for (String anonURI : anons) {
            filterChains.put(anonURI, CustomFilter.ANON);
        }
        filterChains.put(anyRole, CustomFilter.ANY_ROLES);

        factoryBean.setFilterChainDefinitionMap(filterChains);
        return factoryBean;
    }

    /**
     * 权限类型
     */
    static class CustomFilter {
        static final String ANON = "anon";// 不需要拦截
        static final String ANY_ROLES = "anyRoles";
    }
}
